/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum {
    SHORT_PRESS,
    LONG_PRESS
}KeyEvent_t;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
/* Definitions for Task_LED */
osThreadId_t Task_LEDHandle;
const osThreadAttr_t Task_LED_attributes = {
  .name = "Task_LED",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for Task_ScanKeys */
osThreadId_t Task_ScanKeysHandle;
const osThreadAttr_t Task_ScanKeys_attributes = {
  .name = "Task_ScanKeys",
  .stack_size = 256 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for Queue_Keys */
osMessageQueueId_t Queue_KeysHandle;
const osMessageQueueAttr_t Queue_Keys_attributes = {
  .name = "Queue_Keys"
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void AppTask_LED(void *argument);
void AppTask_ScanKeys(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the queue(s) */
  /* creation of Queue_Keys */
  Queue_KeysHandle = osMessageQueueNew (10, sizeof(uint8_t), &Queue_Keys_attributes);

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of Task_LED */
  Task_LEDHandle = osThreadNew(AppTask_LED, NULL, &Task_LED_attributes);

  /* creation of Task_ScanKeys */
  Task_ScanKeysHandle = osThreadNew(AppTask_ScanKeys, NULL, &Task_ScanKeys_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_AppTask_LED */
/**
  * @brief  Function implementing the Task_LED thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_AppTask_LED */
void AppTask_LED(void *argument)
{
  /* USER CODE BEGIN AppTask_LED */

  /* pcQueueGetName(Queue_KeysHandle)和uxQueueSpacesAvailable(Queue_KeysHandle)单独使用时可以用printf打印，共用时输出不对 */
//    uint8_t queueName[30];
//    sprintf(queueName, "Queue Name = %s \n", pcQueueGetName(Queue_KeysHandle));
//    HAL_UART_Transmit(&huart1, queueName, strlen(queueName), HAL_MAX_DELAY);
//
//    uint8_t queueSizeString[30];
//    sprintf(queueSizeString, "Queue size = %lu \n", uxQueueSpacesAvailable(Queue_KeysHandle));
//    HAL_UART_Transmit(&huart1, queueSizeString, strlen(queueSizeString), HAL_MAX_DELAY);

    KeyEvent_t keyEvent;
  /* Infinite loop */
  for(;;)
  {
      /* 串口打印队列数据信息不合适，无限发送，需要配合显示屏输出 */
//      uint8_t buffer[50];
//      sprintf(buffer, "uxQueueMessagesWaiting() = %d", uxQueueMessagesWaiting(Queue_KeysHandle));
//      HAL_UART_Transmit_IT(&huart1, buffer, strlen(buffer));
//
//      sprintf(buffer, "uxQueueSpacesAvailable() = %d", uxQueueSpacesAvailable(Queue_KeysHandle));
//      HAL_UART_Transmit_IT(&huart1, buffer, strlen(buffer));

      if(xQueueReceive(Queue_KeysHandle, &keyEvent, portMAX_DELAY) == pdPASS) {
          switch (keyEvent) {
              case SHORT_PRESS:
                  HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
                  break;
              case LONG_PRESS:
                  for (int i = 0; i < 5; i++) {
                      HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
                      vTaskDelay(pdMS_TO_TICKS(200));
                      HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
                      vTaskDelay(pdMS_TO_TICKS(200));
                  }
                  break;
          }
      }
  }
  /* USER CODE END AppTask_LED */
}

/* USER CODE BEGIN Header_AppTask_ScanKeys */
/**
* @brief Function implementing the Task_ScanKeys thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_AppTask_ScanKeys */
void AppTask_ScanKeys(void *argument)
{
  /* USER CODE BEGIN AppTask_ScanKeys */
  TickType_t pass_start_time;
  const TickType_t  debounce_delay = pdMS_TO_TICKS(20);
  const TickType_t  long_press_delay = pdMS_TO_TICKS(1000);

  KeyEvent_t keyEvent;
  uint8_t btn_state = GPIO_PIN_SET;
  /* Infinite loop */
  for(;;)
  {
      btn_state = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);

      if(btn_state == GPIO_PIN_RESET) {
          vTaskDelay(debounce_delay);
          if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
              pass_start_time = xTaskGetTickCount();

              while(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
                  vTaskDelay(pdMS_TO_TICKS(10 / portTICK_PERIOD_MS));
              }

              TickType_t pass_time = xTaskGetTickCount() - pass_start_time;
              keyEvent = (pass_time >= long_press_delay) ? LONG_PRESS : SHORT_PRESS;
              printf("keyEvent: %s\r\n", (keyEvent == SHORT_PRESS) ? "SHORT" : "LONG");
              xQueueSendToBack(Queue_KeysHandle, &keyEvent, pdMS_TO_TICKS(10));
          }
          vTaskDelay(pdMS_TO_TICKS(10 / portTICK_PERIOD_MS));
      } else {
          // 优先级不同，没有执行任务时需要释放CPU占用
          vTaskDelay(pdMS_TO_TICKS(10));
      }

  }
  /* USER CODE END AppTask_ScanKeys */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

